﻿using System.Collections.Generic;
using ClassLibrary.Configuration.Switch;

namespace NetworkNode.Switching
{
    /// <summary>
    /// @Author Marcin Król
    /// label forwarding table
    /// </summary>
    class SwitchingTable
    {
        //[ingressPortId][ingressVCId] = new SwitchingInfo(egressPortId, egressVCId);
        private readonly Dictionary<int, SwitchingInfo>[] _switchingTable;

        public SwitchingTable(ConfSwitchingTable confSwitchingTable, int portsNo)
        {
            _switchingTable = new Dictionary<int, SwitchingInfo>[portsNo];
            for (int i = 0; i < portsNo; i++)
            {
                _switchingTable[i] = new Dictionary<int, SwitchingInfo>();
            }
            foreach (var record in confSwitchingTable.Records)
            {
                _switchingTable[record.Egress.PortId][record.Egress.VcId] = new SwitchingInfo(record.Ingress.PortId, record.Ingress.VcId);
            }
        }

        public SwitchingInfo Lookup(SwitchingInfo switchingInfo)
        {
            var igressPortId = switchingInfo.PortId;
            var igressVcId = switchingInfo.VcId;

            SwitchingInfo egressSwitchingInfo;
            _switchingTable[igressPortId].TryGetValue(igressVcId, out egressSwitchingInfo);

            return egressSwitchingInfo;
        }

        /// <summary>
        /// Add a new Record to the Switching Table
        /// </summary>
        /// <param name="ingressInfo"></param>
        /// <param name="egressInfo"></param>
        public void AddRecord(SwitchingInfo ingressInfo, SwitchingInfo egressInfo)
        {
            lock (this)
            {
                _switchingTable[ingressInfo.PortId][ingressInfo.VcId] = egressInfo;
                _switchingTable[egressInfo.PortId][egressInfo.VcId] = ingressInfo;
            }
        }

        /// <summary>
        /// Delete Record from the Switching Table
        /// </summary>
        /// <param name="ingressInfo"></param>
        public void DeleteRecord(SwitchingInfo ingressInfo)
        {
            lock (this)
            {
                SwitchingInfo egressInfo = _switchingTable[ingressInfo.PortId][ingressInfo.VcId];
                _switchingTable[ingressInfo.PortId].Remove(ingressInfo.VcId);
                _switchingTable[egressInfo.PortId].Remove(egressInfo.VcId);
            }
        }

        /// <summary>
        /// Update Record in the Switching Table
        /// </summary>
        /// <param name="ingressInfo"></param>
        /// <param name="egressInfo"></param>
        public void UpdateRecord(SwitchingInfo ingressInfo, SwitchingInfo egressInfo)
        {
            lock (this)
            {
                _switchingTable[ingressInfo.PortId][ingressInfo.VcId] = egressInfo;
                _switchingTable[egressInfo.PortId][egressInfo.VcId] = ingressInfo;
            }
        }

        /// <summary>
        /// Returns current state of the switching table
        /// </summary>
        /// <returns></returns>
        public ConfSwitchingTable GetSwitchingTable()
        {
            var confSwitchingTable = new ConfSwitchingTable();

            var list = new List<ConfSwitchingTable.Record>();
            for (var i = 0; i < _switchingTable.Length; i++)
            {
                foreach (var switchingInfoByVcId in _switchingTable[i])
                {
                    list.Add(new ConfSwitchingTable.Record()
                        {
                            Ingress = new ConfSwitchingTable.Record.SwitchingPair()
                                {
                                    PortId = i,
                                    VcId = switchingInfoByVcId.Key
                                },
                            Egress = new ConfSwitchingTable.Record.SwitchingPair()
                                {
                                    PortId = switchingInfoByVcId.Value.PortId,
                                    VcId = switchingInfoByVcId.Value.VcId
                                }
                        });
                }
            }

            var records = new ConfSwitchingTable.Record[list.Count];
            list.CopyTo(records, 0);
            confSwitchingTable.Records = records;

            return confSwitchingTable;
        }
    }
}
